// MainWindow.cs by steb at 1:28 PM 8/10/2008
//
//
// Copyright (C) 2008 Steven Allen
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.Timers;
using Gtk;
using Notifications;
using GConf;

public partial class MainWindow: Gtk.Window
{
	// Initialize the XiimClient Class
	public Xiim.XiimClient xiim = new Xiim.XiimClient();
	// Create the UpdateChat Timer
	private System.Timers.Timer updateChatTimer;
	// Create the notification window
	private Notifications.Notification notify;
	// Create the Gconf client
	private GConf.Client settings;
	// Tray Icon
	private static StatusIcon xiimTray;
	// Create end mark
	private Gtk.TextMark chatEnd = new Gtk.TextMark("chatEnd", false);
	private string inText = "";
	public MainWindow (): base (Gtk.WindowType.Toplevel)
	{
		Build ();
		BuildTray();
		BuildTheme();
		// Set end mark
		chat.Buffer.AddMark(chatEnd, chat.Buffer.EndIter);
		// Initialize the gconf client and set the address box text
		settings = new GConf.Client();
		try
		{
			address.Text = (string)settings.Get("/apps/xiim/address");
		}
		catch
		{
			settings.Set("/apps/xiim/address", "");
		}
		// Initialize and setup the notification
		notify = new Notifications.Notification("Xiim Message:", "", Stetic.IconLoader.LoadIcon(this, "XiimIcon", IconSize.Dialog, 64));
		notify.Closed += delegate { xiimTray.Blinking = false; };
		// Initialize and setup the updateChat timer
		updateChatTimer = new System.Timers.Timer();
        updateChatTimer.Elapsed += new ElapsedEventHandler(updateChat);
        updateChatTimer.Interval = 100;
		// Give the address bar focus
		address.HasFocus = true;
	}
	
	protected void OnDeleteEvent (object sender, DeleteEventArgs a)
	{
		Application.Quit ();
		a.RetVal = true;
	}

	private void OnConnectBtnClicked (object sender, System.EventArgs e)
	{
		if (connectBtn.Label == "Disconnect")
		{
			xiim.disconnect();
			updateChatTimer.Stop();
			entry.Sensitive = false;
			sendBtn.Sensitive = false;
			address.Sensitive = true;
			chat.Sensitive = false;
			connectBtn.Label = "Connect";
			address.HasFocus = true;
		}
		else
		{
			if (xiim.connect(address.Text))
			{
				updateChatTimer.Start();
				entry.Sensitive = true;
				sendBtn.Sensitive = true;
				chat.Sensitive = true;
				address.Sensitive = false;
				entry.HasFocus = true;
				connectBtn.Label = "Disconnect";
				System.Object location = new System.Object();
				location = address.Text;
				settings.Set("/apps/xiim/address", location);
			}
			else
			{
				chat.Buffer.Text = "::Can't connect to " + address.Text + "::\n";
			}
		}
	}

	private void OnSendBtnClicked (object sender, System.EventArgs e)
	{
		xiim.sendData(entry.Text);
		entry.Text = "";
	}
	private void updateChat(object sender, ElapsedEventArgs e)
	{
		lock (inText)
		{
			inText = xiim.receiveData();
			if (!String.IsNullOrEmpty(inText))
			{
				lock (chat)
				{
					// Set chat text
					chat.Buffer.Text += inText;
					// Scroll chat text
					lock (chatEnd)
					{
						chat.Buffer.MoveMark(chatEnd, chat.Buffer.GetIterAtLine(chat.Buffer.LineCount));
						chat.ScrollMarkOnscreen(chatEnd);
					}
					if (inText == ":: Connection Closed ::")
					{
						updateChatTimer.Stop();
						object a = new object();
						EventArgs b = new EventArgs();
						OnConnectBtnClicked(a, b);
					}
				}

				// libnotify popup
				if (!this.Visible)
				{
					notify.Body = inText;
					notify.Show();
					xiimTray.Blinking = true;
				}
			}
		}
	}

	protected virtual void OnAddressKeyReleaseEvent (object o, Gtk.KeyReleaseEventArgs args)
	{
		if (args.Event.Key == Gdk.Key.Return)
		{
			object a = new object();
			EventArgs b = new EventArgs();
			OnConnectBtnClicked(a, b);
		}
	}

	protected virtual void OnEntryKeyReleaseEvent (object o, Gtk.KeyReleaseEventArgs args)
	{
		if (args.Event.Key == Gdk.Key.Return)
		{
			object a = new object();
			EventArgs b = new EventArgs();
			OnSendBtnClicked(a, b);
		}
	}
	
	protected virtual void OnCloseBtnClicked (object sender, System.EventArgs e)
	{
		Application.Quit();
	}
	
	private void BuildTray()
	{
		Gdk.Pixbuf trayIcon = Stetic.IconLoader.LoadIcon(this, "XiimIconSmall", Gtk.IconSize.SmallToolbar, 24);
		xiimTray = new StatusIcon(trayIcon);
		xiimTray.Activate += delegate { showHide(); };
		xiimTray.Visible = true;
		xiimTray.Tooltip = "Xiim Is a Messenger";
		// Create Popup
        Menu trayMenu = new Menu();
		//Quit
        ImageMenuItem menuItemQuit = new ImageMenuItem ("Quit");
        menuItemQuit.Image = new Gtk.Image(Stock.Quit, IconSize.Menu);
        menuItemQuit.Activated += delegate { Application.Quit(); };
        trayMenu.Add(menuItemQuit);
		// Show+Hide
		ImageMenuItem menuItemShow = new ImageMenuItem ("Show/Hide");
		menuItemShow.Image = new Gtk.Image(Stock.Open, IconSize.Menu);
        menuItemShow.Activated += delegate { showHide(); };
		trayMenu.Add(menuItemShow);
		xiimTray.PopupMenu += delegate { trayMenu.ShowAll(); trayMenu.Popup(); };
	}
	private void BuildTheme()
	{
		
		// Make colors
		Gdk.Color black = new Gdk.Color(0, 0, 0);
		//Gdk.Color red = new Gdk.Color(0xff, 0, 0);
		//Gdk.Color green = new Gdk.Color(0, 0xff, 0);
		//Gdk.Color blue = new Gdk.Color(0, 0, 0xff);
		Gdk.Color white = new Gdk.Color(0xff, 0xff, 0xff);
		Gdk.Color light_gray = new Gdk.Color(0xaa, 0xaa, 0xaa);
		Gdk.Color gray = new Gdk.Color(0x33, 0x33, 0x33);
		Gdk.Color dark_gray = new Gdk.Color(0x11, 0x11, 0x11);
		
		// Color Chat Box
		chat.ModifyText(StateType.Normal, white);
		chat.ModifyBase(StateType.Normal, dark_gray);
		chat.ModifyText(StateType.Insensitive, gray);
		chat.ModifyBase(StateType.Insensitive, dark_gray);
		// Color Entry Box
		entry.ModifyText(StateType.Normal, white);
		entry.ModifyBase(StateType.Normal, gray);
		entry.ModifyText(StateType.Insensitive, light_gray);
		entry.ModifyBase(StateType.Insensitive, dark_gray);
		// Color Title
		title.ModifyFg(StateType.Normal, white);
		// Color Address Box
		address.ModifyText(StateType.Normal, white);
		address.ModifyBase(StateType.Normal, gray);
		address.ModifyText(StateType.Insensitive, light_gray);
		address.ModifyBase(StateType.Insensitive, dark_gray);
		//Main Window
		this.ModifyBg(StateType.Normal, black);
		// Set window location
		Orientation trayOrient = new Gtk.Orientation();
		Gdk.Screen trayScreen = new Gdk.Screen(IntPtr.Zero);
		Gdk.Rectangle trayRect = new Gdk.Rectangle();
		xiimTray.GetGeometry(out trayScreen, out trayRect, out trayOrient);
		if (trayRect.Location.Y < Screen.Height / 3)
		{
			if (trayRect.Location.X < Screen.Width / 3)
				this.GdkWindow.Move(0, 0);
			else if (trayRect.Location.X < 2 * Screen.Width / 3)
				this.GdkWindow.Move((Screen.Width - this.WidthRequest) / 2, 0);
			else
				this.GdkWindow.Move(Screen.Width - this.WidthRequest, 0);
		}
		else if (trayRect.Location.Y < (2 * Screen.Height) / 3)
		{
			if (trayRect.Location.X < Screen.Width / 3)
				this.GdkWindow.Move(0, (Screen.Height - this.HeightRequest) / 2);
			else if (trayRect.Location.X < 2 * Screen.Width / 3)
				this.GdkWindow.Move((Screen.Width - this.WidthRequest) / 2, (Screen.Height - this.HeightRequest) / 2);
			else
				this.GdkWindow.Move(trayRect.Left - this.WidthRequest, (Screen.Height - this.HeightRequest) / 2);
		}
		else
		{
			if (trayRect.Location.X < Screen.Width / 3)
				this.GdkWindow.Move(0, trayRect.Top - this.HeightRequest);
			else if (trayRect.Location.X < 2 * Screen.Width / 3)
				this.GdkWindow.Move((Screen.Width - this.WidthRequest) / 2, trayRect.Top - this.HeightRequest);
			else
				this.GdkWindow.Move(Screen.Width - this.WidthRequest, trayRect.Top - this.HeightRequest);
		}

		// Keep window on top
		this.GdkWindow.KeepAbove = true;
		// Set window opacity
		this.GdkWindow.Opacity = 0.9;
		// Make window appear on all desktops
		this.GdkWindow.Stick();
	}
	private void showHide()
	{
		if (this.Visible)
		{
			this.Visible = false;
		}
		else
		{
			this.Visible = true;
			this.GdkWindow.KeepAbove = true;
		}	
	}

	protected virtual void OnFocusInEvent (object o, Gtk.FocusInEventArgs args)
	{
		this.GdkWindow.Opacity = .9;
	}

	protected virtual void OnFocusOutEvent (object o, Gtk.FocusOutEventArgs args)
	{
		this.GdkWindow.Opacity = .5;
	}
}